//
// async_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2012 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>

using boost::asio::ip::tcp;
using namespace std;

class session
{
	public:
		session(boost::asio::io_service& io_service)
		: socket_(io_service)
		{
		}

		tcp::socket& socket()
		{
			return socket_;
		}

		void start()
		{
		socket_.async_read_some(boost::asio::buffer(data_, max_length),
		boost::bind(&session::handle_read, this,
		boost::asio::placeholders::error,
		boost::asio::placeholders::bytes_transferred));

		}

	private:
		void handle_read(const boost::system::error_code& error,
		size_t bytes_transferred)
		{
			if (!error)
			{
				tcp::endpoint sender_endpoint;
				int sizeSource = 5,
				  sizeDestination = 5,
				  sizeProtocolType = 2,
				  sizePrimitiveName = 2,
				  informationElement = 2,
				  informationElementValue = 3,
				  start,
				  end;
				cout << "#######################" << endl;
				start = 0;
				end = sizeSource;
				cout << "Source (" << end - start << "):\t\t";
				for (int i = start; i < end; i++)
					cout << data_[i];
				cout << endl;
				start += sizeSource;
				end += sizeDestination;
				cout << "Destination (" << end - start << "):\t";
				for (int i = start; i < end; i++)
					cout << data_[i];
				cout << endl;
				start += sizeDestination;
				end += sizeProtocolType;
				cout << "Protocol Type (" << end - start << "):\t";
				for (int i = start; i < end; i++)
					cout <<  data_[i];
				cout << endl;
				start += sizeProtocolType;
				end += sizePrimitiveName;
				cout << "Primitive Name (" << end - start << "):\t";
				for (int i = start; i < end; i++)
					cout << data_[i];
				cout << endl;
				start += sizePrimitiveName;
				end += informationElement;
				cout << "Information Element (" << end - start << "):";
				for (int i = start; i < end; i++)
					cout << data_[i];
				cout << endl;
				start += informationElement;
				end += informationElementValue;
				cout << "IE Value (" << end - start << "):\t\t";
				for (int i = start; i < end; i++)
					cout << data_[i];
				cout << endl;
				boost::asio::async_write(socket_,
				boost::asio::buffer(data_, bytes_transferred),
				boost::bind(&session::handle_write, this,
				boost::asio::placeholders::error));
			}
			else
			{
				delete this;
			}
		}

	void handle_write(const boost::system::error_code& error)
	{
		if (!error)
		{
			socket_.async_read_some(boost::asio::buffer(data_, max_length),
			boost::bind(&session::handle_read, this,
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
		}
		else
		{
			delete this;
		}
	}

	tcp::socket socket_;
	enum { max_length = 1024 };
	char data_[max_length];
};

class server
{
	public:
		server(boost::asio::io_service& io_service, short port)
		: io_service_(io_service),
		acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
		{
			start_accept();
		}

	private:
		void start_accept()
		{
			session* new_session = new session(io_service_);
			acceptor_.async_accept(new_session->socket(),
			boost::bind(&server::handle_accept, this, new_session,
			boost::asio::placeholders::error));
		}

		void handle_accept(session* new_session,
		const boost::system::error_code& error)
		{
			if (!error)
			{
			new_session->start();
			}
			else
			{
			delete new_session;
			}

			start_accept();
		}

		boost::asio::io_service& io_service_;
		tcp::acceptor acceptor_;
};

int main(int argc, char* argv[])
{
	try
	{
		if (argc != 2)
		{
		std::cerr << "Usage: async_tcp_echo_server <port>\n";
		return 1;
		}

		boost::asio::io_service io_service;

		using namespace std; // For atoi.
		server s(io_service, atoi(argv[1]));

		io_service.run();
		}
	catch (std::exception& e)
	{
		std::cerr << "Exception: " << e.what() << "\n";
	}

	return 0;
}
